﻿
using System;
using System.Collections.Generic;
using élénkPróbája.native;
using élénkPróbája.native.rule;
using élénkPróbája.validators.adaptors;

namespace élénkPróbája.extentions
{
    public static class LitmusCollectionValidatorExtensions
    {
        /// <summary>
        /// Associates an instance of IValidator with the current property rule and is used to validate each item within the collection.
        /// </summary>
        /// <param name="validator">The validator to use</param>
        public static ICollectionValidatorRuleBuilder<T, TCollectionElement> SetCollectionValidator<T, TCollectionElement>(this ITestAdmin<T, IEnumerable<TCollectionElement>> testAdmin, IValidator<TCollectionElement> validator)
        {
            var adaptor = new SubCollectionValidatorAdaptor(validator);
            testAdmin.SetValidator(adaptor);
            return new CollectionValidatorRuleBuilder<T, TCollectionElement>(testAdmin, adaptor);
        }

        public static ICollectionValidatorRuleBuilder<T, TCollectionElement> SetCollectionValidator<T, TCollectionElement, TValidator>(this ITestAdmin<T, IEnumerable<TCollectionElement>> ruleBuilder, Func<T, TValidator> validator)
            where TValidator : IValidator<TCollectionElement>
        {
            var adaptor = new SubCollectionValidatorAdaptor(parent => validator((T)parent), typeof(TValidator));
            ruleBuilder.SetValidator(adaptor);
            return new CollectionValidatorRuleBuilder<T, TCollectionElement>(ruleBuilder, adaptor);
        }

        public interface ICollectionValidatorRuleBuilder<T, TCollectionElement> : ITestAdminOptions<T, IEnumerable<TCollectionElement>>
        {
            ICollectionValidatorRuleBuilder<T, TCollectionElement> Where(Func<TCollectionElement, bool> predicate);
        }

        private class CollectionValidatorRuleBuilder<T, TCollectionElement> : ICollectionValidatorRuleBuilder<T, TCollectionElement>
        {
            ITestAdmin<T, IEnumerable<TCollectionElement>> ruleBuilder;
            SubCollectionValidatorAdaptor adaptor;

            public CollectionValidatorRuleBuilder(ITestAdmin<T, IEnumerable<TCollectionElement>> ruleBuilder, SubCollectionValidatorAdaptor adaptor)
            {
                this.ruleBuilder = ruleBuilder;
                this.adaptor = adaptor;
            }

            public ITestAdminOptions<T, IEnumerable<TCollectionElement>> SetValidator(ILitPropertyValidator validator)
            {
                return ruleBuilder.SetValidator(validator);
            }

            public ITestAdminOptions<T, IEnumerable<TCollectionElement>> SetValidator(IValidator<IEnumerable<TCollectionElement>> validator)
            {
                return ruleBuilder.SetValidator(validator);
            }

            public ITestAdminOptions<T, IEnumerable<TCollectionElement>> SetValidator<TValidator>(Func<T, TValidator> validatorProvider)
                where TValidator : IValidator<IEnumerable<TCollectionElement>>
            {
                return ruleBuilder.SetValidator(validatorProvider);
            }
             
            public ITestAdminOptions<T, IEnumerable<TCollectionElement>> Configure(Action<PropRule> configurator)
            {
                return ((ITestAdminOptions<T, IEnumerable<TCollectionElement>>)ruleBuilder).Configure(configurator);
            }

            public ICollectionValidatorRuleBuilder<T, TCollectionElement> Where(Func<TCollectionElement, bool> predicate)
            {
                predicate.Guard("Cannot pass null to Where.");
                adaptor.Predicate = x => predicate((TCollectionElement)x);
                return this;
            }

        }
    }
}